/*
 * athlete.java
 *
 * Created on March 5, 2006, 8:30 PM
 *
 * To change this template, choose Tools | Options and locate the template under
 * the Source Creation and Management node. Right-click the template and choose
 * Open. You can then make changes to the template in the Source Editor.
 */


/**
 *
 * @author Sujal Bista
 */

import java.util.Vector;
import java.util.Collections;
import java.lang.Double;
import java.util.StringTokenizer;

public class athlete 
{
    private String group;
    private String gender;
    private String event;
    private String name;
    private String nandu;
    private int order;
    private String reason;
    private int diffTime;
    
    //data judges returned 
    //for judgeA (x=time in millisec, y=code)
    //for judgeB (x=score,y=0)
    //for judgeC (x=+100 for new nandu, +50 for connected one,y= (0:=fail 1:=true) )
    private Vector judgesData[];
    private judge.judgeType judgesType[];
    private boolean judgesConnected[];
  
    
    /** Creates a new instance of athlete */
    public athlete(String group_in, String gender_in, String event_in, String name_in) 
    {
        judgesData=new Vector[globalData.totalJudges];
        judgesType=new judge.judgeType[globalData.totalJudges];
        judgesConnected=new boolean[globalData.totalJudges];
        
        for(int i=0;i<globalData.totalJudges;i++)
        {
            judgesData[i]=new Vector(0,10);
            judgesType[i]=judge.judgeType.judgeB;
            judgesConnected[i]=false;
        }
        
        group = group_in;
        gender = gender_in;
        event = event_in;
        name = name_in;
    }

    //sets the judges type
    public void setJudgeType(int judgeIndex, judge.judgeType type)
    {
        judgesType[judgeIndex] = type;
    }

    //check if the judges are connected
    public void setJudgeConnected(int judgeIndex, boolean connected)
    {
        judgesConnected[judgeIndex] = connected;
    }

    //check if the judges are connected
    public boolean getJudgeConnected(int judgeIndex)
    {
        return judgesConnected[judgeIndex];
    }


    public judge.judgeType getJudgeType(int judgeIndex)
    {
        return judgesType[judgeIndex];
    }
    //set create the judge type string
    public String getJudgeTypeString()
    {
        String judgeTypeString=new String();

        for(int i=0;i<globalData.totalJudges;i++)
        {
            switch(judgesType[i])
            {
                case judgeA:
                    judgeTypeString+="0 ";
                    break;
                case judgeB:
                    judgeTypeString+="1 ";
                    break;
                case judgeC:
                    judgeTypeString+="2 ";
                    break;
            }
        }
        return judgeTypeString;
    }

    //set judge type
    public void setJudgeTypeString(String data)
    {
        if(data.length()==0)
            return;

        int index,jIndex=0;
        while(data.indexOf(' ')!=-1)
        {
            index=data.indexOf(' ');
            String value=data.substring(0, index);
            data=data.substring(index+1);

            int valueInt=Integer.valueOf(value);

            switch(valueInt)
            {
                case 0:
                    judgesType[jIndex]=judge.judgeType.judgeA;
                    break;
                case 1:
                    judgesType[jIndex]=judge.judgeType.judgeB;
                    break;
                case 2:
                    judgesType[jIndex]=judge.judgeType.judgeC;
                    break;
            }
            jIndex=jIndex+1;
        }
    }

    //set create the judge type string
    public String getJudgeConnectedString()
    {
        String judgeConnectedString=new String();
        for(int i=0;i<globalData.totalJudges;i++)
        {
            if(judgesConnected[i])
                judgeConnectedString+="1 ";
            else
                judgeConnectedString+="0 ";
        }
        return judgeConnectedString;
    }

    //set judge type
    public void setJudgeConnectedString(String data)
    {
        if(data.length()==0)
            return;

        int index,jIndex=0;
        while(data.indexOf(' ')!=-1)
        {
            index=data.indexOf(' ');
            String value=data.substring(0, index);
            data=data.substring(index+1);

            int valueInt=Integer.valueOf(value);

            switch(valueInt)
            {
                case 0:
                    judgesConnected[jIndex]=false;
                    break;
                case 1:
                    judgesConnected[jIndex]=true;
                    break;
            }
            jIndex=jIndex+1;
        }
    }


    //clear the judge data
    public void clearJudgesVector(boolean ignoreHeadJudge)
    {
        int judgesCount=globalData.totalJudges;
        if(ignoreHeadJudge)
            judgesCount=globalData.totalJudges-1;

        for(int i=0;i<judgesCount;i++)
             if (judgesData[i] != null)
                judgesData[i].clear();
    }
    
    //sets the judges data
    public void setJudgeVector(int judgeIndex, Vector data)
    {
        judgesData[judgeIndex] = data;
    }

    //gets the judges data
    public Vector getJudgeVector(int judgeIndex)
    {
        return judgesData[judgeIndex];
    }

    //adds the judges data
    public void addJudgeData(int judgeIndex, point data)
    {
        judgesData[judgeIndex].addElement(data);
    }

    //removes the judges data
    public point removeJudgeData(int judgeIndex, int removeIndex)
    {
        return ((point)judgesData[judgeIndex].remove(removeIndex));
    }

    //get the judges data
    public point getJudgeData(int judgeIndex, int dataIndex)
    {
        return ((point)judgesData[judgeIndex].elementAt(dataIndex));
    }

    //set the judges data
    public void setJudgeData(int judgeIndex, int dataIndex, point data)
    {
        ((point)judgesData[judgeIndex].elementAt(dataIndex)).x=data.x;
        ((point)judgesData[judgeIndex].elementAt(dataIndex)).y=data.y;
    }
    
    //sets the name
    public void setName(String tName)
    {
        name=tName;
    }

    public void setNandu(String data)
    {
        nandu=data;
    }

    public void setReason(String data)
    {
        reason=data;
    }

    public void setOrder(int data)
    {
        order=data;
    }
    
    public String getName()
    {
        return name;
    }

    //returns entire nandu string
    public boolean hasCompeted()
    {
        for(int i=0;i<globalData.totalJudges;i++)
        {
            if(judgesData[i].size()>0)
                return true;
        }
        return false;
    }
    
    //returns entire nandu string
    public String getNandu()
    {
        return nandu;
    }
    
    //returns the reason
     public String getReason()
    {
        return reason;
    }

    //check if the event is true
    public boolean isEvent(String eventName)
    {
        return event.equals(eventName);
    }
    
    //returns nandu code based on the index
    public String getNandu(int i)
    {
        String tempNandu=new String(nandu) ;
        String value="";
        int count=0;
        while(tempNandu.length()!=0)
        {
            
            if(tempNandu.indexOf(",")==-1)
            {
                value=tempNandu;
                tempNandu="";
            }
            else
            {
               value=tempNandu.substring(0, tempNandu.indexOf(","));
               tempNandu=tempNandu.substring(tempNandu.indexOf(",")+1);
            }
            if(count==i)
                break;
            count++;
        }
        return value;
    }
    
    //returns total nandu count
    public int getNanduCount()
    {
        String tempNandu=new String(nandu) ;
        int count=0;
        while(tempNandu.length()!=0)
        {
            String value;
            if(tempNandu.indexOf(",")==-1)
            {
                value=tempNandu;
                tempNandu="";
            }
            else
            {
               value=tempNandu.substring(0, tempNandu.indexOf(","));
               tempNandu=tempNandu.substring(tempNandu.indexOf(",")+1);
            }
            count++;
        }
        return count;
    }
    
    //includes sub parts of Nandu
    public int getMovementsCount()
    {
        int count=0;
        for(int i=getNanduCount()-1;i>=0;i--)
        {
            nanduData.nandu nd=globalData.nanduList.find(getNandu(i));
            String abc=getNandu(i);
            if(nd==null)
                nd=null;
            count+=nd.getTotalMovements();
        }
        return count;
    }    
        
    //prints athlete to string
    //has to be in following format
    //[nameLength]:[name]:[nandu]
    public String toString()
    {
        String str;
        str=Integer.toString(name.length())+":";
        str+=name+":";
        str+=nandu;
        return str;
    }
    
    
    //reads athlete from string
    //has to be in following format
    //[nameLength]:[name]:[nandu]
    public void fromString(String str)
    {

        int index,i,j;
        
        //"12:Eric Cartman: 324C+l,312B";
        //read name length
        index=str.indexOf(':');
        int nameLength=Integer.valueOf(str.substring(0, index));
        str=str.substring(index+1);
        
        //read Name
        name=str.substring(0,nameLength);
        str=str.substring(nameLength+1);
       
        //add Nandu
        nandu=str;
    }
    
   
    //mostly for tradional judging
    //to display result from all judges
    public String getJudgesData(int scoringSystem)
    {
        String data=new String();
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeB && judgesData[i].size()>0)
            {
                Double score = new Double(((point)judgesData[i].lastElement()).x);
                data+=String.format("%.2f", score)+" ";                    
            }
        }
        //for head judge
        if(judgesData[(globalData.totalJudges-1)].size()>0) 
        {
            Double score = (Double) judgesData[(globalData.totalJudges-1)].firstElement();
            if(score!=0.0)
                data+=String.format("%.2f", score)+" ";
        }
        return data;
    }

    //calculate final score of judge B based on the Scoring system
    public double calculateBScore(int scoringSystem)
    {
        double BScore = 0.0;
        int i;
        Vector BScores = new Vector();
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeB && judgesData[i].size()>0) {
                Double score = new Double(((point)judgesData[i].lastElement()).x);
                BScores.addElement(score);
            }
        }
        
        // Head Judge's B-score
        if (judgesData[(globalData.totalJudges-1)].size() > 0) {
            Double score = (Double) judgesData[(globalData.totalJudges-1)].firstElement();
            if(score!=0.0)
                BScores.addElement(score);
        }
        
        if (BScores.size() > 0) {
            // if there are more than 3 Overall Scores, remove highest and lowest
            if (BScores.size() > 2) {
                Collections.sort(BScores);
                BScores.removeElementAt(BScores.size() - 1); // remove last
                BScores.removeElementAt(0); // remove first
            }
            
            // take the average of the scores
            double BScore_sum = 0.0;
            int k;
            for (k = 0; k < BScores.size(); k++) {
                BScore_sum += ((Double) BScores.elementAt(k)).doubleValue();
            }
            BScore = BScore_sum / BScores.size();
        }
        
        return BScore;
    }
    //calculate number of mistakes
    public int numMistakes()
    {
        int num = 0;
        int numJudgeA=0;
        Vector raw_deductions = new Vector();

        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
            {
               raw_deductions.addElement(new athlete.Deduction(i, judgesData[i]));
               if(judgesConnected[i]==true)
                    numJudgeA++;
            }
        }
        
        Vector final_deductions = athlete.computeADeductions(raw_deductions);
        
        int b;
        for (b = 0; b < final_deductions.size(); b++) {
            Vector bin = (Vector) final_deductions.elementAt(b);

            if (bin.size() > 1 || numJudgeA == 1) { // more than one judge agrees
                num++;
            }
        }
        return num;
    }
    
    public String MarshalRawA()
    {
        String result = "";
        Vector raw_deductions = new Vector();

        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
                raw_deductions.addElement(new athlete.Deduction(i, judgesData[i]));
        }
        
        Vector final_deductions = athlete.computeADeductions(raw_deductions);
        
        int b;
        for (b = 0; b < final_deductions.size(); b++)
        {
            Vector bin = (Vector) final_deductions.elementAt(b);
            
            int c;
            for (c = 0; c < bin.size(); c++) 
            {
                DeductPoint d = (DeductPoint) bin.get(c);
                result += "(" + d.judgeIndex+","+d.time+","+ d.code+ ") ";
            }
        }
        
        return result;
    }
    
    public void UnmarshalRawA(String raw)
    {
        StringTokenizer tok = new StringTokenizer(raw);
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
                judgesData[i] = new Vector();
        }
        while (tok.hasMoreTokens()) {
            String triplet = tok.nextToken();
            StringTokenizer subtok = new StringTokenizer(triplet, "(,)");
            int judgeIndex = Integer.parseInt(subtok.nextToken());
            point p = new point();
            p.x = Integer.parseInt(subtok.nextToken());
            p.y = Integer.parseInt(subtok.nextToken());
            judgesData[judgeIndex].add(p);
        }
    }
    
    public String MarshalAgreeA()
    {
        String result = "";
        Vector raw_deductions = new Vector();

        int numJudgeA=0;
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
            {
                raw_deductions.addElement(new athlete.Deduction(i, judgesData[i]));
                if(judgesConnected[i]==true)
                    numJudgeA++;
            }
        }
        
        Vector final_deductions = athlete.computeADeductions(raw_deductions);
        
        int b;
        for (b = 0; b < final_deductions.size(); b++) {
            Vector bin = (Vector) final_deductions.elementAt(b);

            if (bin.size() > 1 || numJudgeA==1) { // more than one judge agrees
                int code = ((DeductPoint) bin.get(0)).code;
                if (code != 0) {

                    //converts judge A's code to point
                    double value = codeToPoint(code);

                    result += "-" + value + " ";
                }
            }
        }
         
        return result;
    }

    public String getSummaryJudgeA()
    {
       String result = "";
        Vector raw_deductions = new Vector();

        int numJudgeA=0;
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
            {
                raw_deductions.addElement(new athlete.Deduction(i, judgesData[i]));
                if(judgesConnected[i]==true)
                    numJudgeA++;
            }
        }
        
        Vector final_deductions = athlete.computeADeductions(raw_deductions);
        
        int b;
        for (b = 0; b < final_deductions.size(); b++) {
            Vector bin = (Vector) final_deductions.elementAt(b);

            if (bin.size() > 1 || numJudgeA==1) { // more than one judge agrees
                int code = ((DeductPoint) bin.get(0)).code;
                if (code != 0) {

                    result += Integer.toString(code)+" ";
                }
            }
        }
         
        return result;
    }   

    //converts judge A's code to point
    private double codeToPoint(int code)
    {
        double deductValue=0.0;
        switch (code) 
        {
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 71:
            case 74:
            case 86:
            case 87:
            case 88:
                deductValue = 0.2;
                break;

            case 72:
            case 75:
            case 84:
                deductValue = 0.3;
                break;

            case -1:
            case 00:
                deductValue = 0.0;
                break;
                
            case 85:
                deductValue = 0.5;
                break;

            default:
                deductValue = 0.1;
                break;
        }
        return deductValue;        
    }


    public double calculateAScore()
    {
        double AScore=5.0;
        
        if(globalData.scoringSystem==1)  //1 New Traditional System
            AScore=5.0;
            
        Vector raw_deductions = new Vector();

        int numJudgeA=0;
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeA)
            {
                raw_deductions.addElement(new athlete.Deduction(i, judgesData[i]));
                if(judgesConnected[i]==true)
                    numJudgeA++;
            }
        }
        
        Vector final_deductions = athlete.computeADeductions(raw_deductions);
        
        int b;
        for (b = 0; b < final_deductions.size(); b++) {
            Vector bin = (Vector) final_deductions.elementAt(b);

            if (bin.size() > 1 || numJudgeA==1) { // more than one judge agrees
                int code = ((DeductPoint) bin.get(0)).code;

                //converts judge A's code to point
                AScore -= codeToPoint(code);
            }
        }
        
        if (AScore < 0)
            AScore = 0.0;
        
        return AScore;
    }
    
    public String MarshalRawC()
    {
        String result = "";
        int i,j;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeC)
            {
                for(j=0;j<judgesData[i].size();j++)
                {
                    point p=(point)judgesData[i].get(j);
                    //judge index, positon(not needed), data(1 = success, 0=fail)
                    result+="(" + i +","+Integer.toString((int)p.x)+","+Integer.toString((int)p.y)+") ";
                }
            }
        }
        return result;
    }
    
    public void UnmarshalRawC(String raw)
    {
        StringTokenizer tok = new StringTokenizer(raw);
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeC)
                judgesData[i] = new Vector();
        }
        while (tok.hasMoreTokens()) 
        {
            String triplet = tok.nextToken();
            StringTokenizer subtok = new StringTokenizer(triplet, "(,)");
            int judgeIndex = Integer.parseInt(subtok.nextToken());
            
            point p = new point();
            p.x = Integer.parseInt(subtok.nextToken());
            p.y = Integer.parseInt(subtok.nextToken());
            judgesData[judgeIndex].add(p);
        }
    }
    
    public String MarshalAgreeC()
    {
        String result = "";
        
        int i,j,k,count,judgeDataIndex=0;

        int totalJudges=0,minJudgeCount=2;
        //if more than two judges think its okay
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {
            if(judgesType[i]==judge.judgeType.judgeC && judgesConnected[i]==true)
            {
               totalJudges++;
            }
        }
        if(minJudgeCount>totalJudges)
            minJudgeCount=totalJudges;

        if(minJudgeCount>0)
        {
            //check all nandu
            for(j=0;j<getNanduCount();j++)
            {
                nanduData.nandu nanduDesc=globalData.nanduList.find(getNandu(j));
                if(j>0)
                    result+=", ";
                result+=getNandu(j)+":";

                //go through all the movement of the nandu
                for(k=0;k<nanduDesc.getTotalMovements();k++)
                {
                    count=0;
                    //if more than two judges think its okay
                    for (i = 0; i < (globalData.totalJudges-1); i++)
                    {
                        if(judgesType[i]==judge.judgeType.judgeC && j<judgesData[i].size())
                        {
                            point p=(point)judgesData[i].get(judgeDataIndex);
                            if(p.y==1)  //if success increase the counter
                                count++;
                        }
                    }

                    if(count>=minJudgeCount)
                        result+="P";
                    else
                        result+="F";

                    //increase the index of the data
                    judgeDataIndex++;
                }
            }
        }
        
        return result;
    }
    
    public double calculateCScore()
    {
        double score=0.0;
        double difficultyScore = 0.0;
        double transitionScore = 0.0;
        double failDifficultyScore=0.0;
        double failTransitionScore=0.0;
        double totalDifficultyScore=0.0;
        double totalTransitionScore=0.0;
        double maxDifficultyScore=1.4;
        double maxTransitionScore=0.6;
        int i,j,count,k;

        int totalJudges=0,minJudgeCount=2;
        //if more than two judges think its okay
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {
            if(judgesType[i]==judge.judgeType.judgeC && judgesConnected[i]==true)
            {
               totalJudges++;
            }
        }
        if(minJudgeCount>totalJudges)
            minJudgeCount=totalJudges;

        if(minJudgeCount>0)
        {
            //check all nandu
            int totalMovementsCount=getMovementsCount();
            int totalNanduCount=getNanduCount();
            for(j=0;j<totalMovementsCount; j++)
            {
                count=0;
                //if more than two judges think its okay
                for (i = 0; i < (globalData.totalJudges-1); i++)
                {
                    if(judgesType[i]==judge.judgeType.judgeC && j<judgesData[i].size())
                    {
                        point p=(point)judgesData[i].get(j);
                        if(p.y==1)  //if success increase the counter
                            count++;
                    }
                }

                int l=j;
                for(k=0;k<totalNanduCount;k++)
                {
                    nanduData.nandu nanduDesc=globalData.nanduList.find(getNandu(k));
                    if(l<nanduDesc.getTotalMovements())
                    {
                        double currPoint=nanduDesc.getPoint(l);

                        if(l % 2 == 1)//for transistion
                        {
                            //new rule for capping nandu score
                            if(currPoint>maxTransitionScore-totalTransitionScore)
                                currPoint=maxTransitionScore-totalTransitionScore;
                            
                            if(count>=minJudgeCount)
                                transitionScore += currPoint;
                            else
                                failTransitionScore+= currPoint;
                            totalTransitionScore+= currPoint;

                        }
                        else    //for difficulty
                        {
                            //new rule for capping nandu score
                            if(currPoint>maxDifficultyScore-totalDifficultyScore)
                            {
                                   currPoint=maxDifficultyScore-totalDifficultyScore;
                            }
                            
                            if(count>=minJudgeCount)
                                difficultyScore += currPoint;
                            else
                                failDifficultyScore+= currPoint;
                            totalDifficultyScore+= currPoint;
                        }
                        break;
                    }
                    l-=nanduDesc.getTotalMovements();
                }


            }

            if (totalTransitionScore > maxTransitionScore)
                totalTransitionScore = maxTransitionScore;
            if (totalDifficultyScore > maxDifficultyScore)
                totalDifficultyScore = maxDifficultyScore;

            //sujal : some athlete put more than 2.0 nandu. So this deduction system is made
            if(failTransitionScore>maxTransitionScore)
                failTransitionScore=maxTransitionScore;
            if(failTransitionScore<0)
                failTransitionScore=0.0;
            transitionScore=totalTransitionScore-failTransitionScore;

            if(failDifficultyScore>maxDifficultyScore)
                failDifficultyScore=maxDifficultyScore;
            if(failDifficultyScore<0)
                failDifficultyScore=0;
            difficultyScore=totalDifficultyScore-failDifficultyScore;
            
        }

        score = transitionScore + difficultyScore;

        return score;        
    }
    
    //calculates number of suffessful b level or greater nandu
    public int calculateSuccessfulBLevelOrGreaterNandu()
    {
        int bLevelNanduCount=0;
        int i,j,count,k;

        int totalJudges=0,minJudgeCount=2;
        //if more than two judges think its okay
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {
            if(judgesType[i]==judge.judgeType.judgeC && judgesConnected[i]==true)
            {
               totalJudges++;
            }
        }
        if(minJudgeCount>totalJudges)
            minJudgeCount=totalJudges;

        if(minJudgeCount>0)
        {
            //check all nandu
            int totalMovementsCount=getMovementsCount();
            int totalNanduCount=getNanduCount();
            for(j=0;j<totalMovementsCount; j++)
            {
                count=0;
                //if more than two judges think its okay
                for (i = 0; i < (globalData.totalJudges-1); i++)
                {
                    if(judgesType[i]==judge.judgeType.judgeC && j<judgesData[i].size())
                    {
                        point p=(point)judgesData[i].get(j);
                        if(p.y==1)  //if success increase the counter
                            count++;
                    }
                }

                int l=j;
                for(k=0;k<totalNanduCount;k++)
                {
                    nanduData.nandu nanduDesc=globalData.nanduList.find(getNandu(k));
                    if(l<nanduDesc.getTotalMovements())
                    {
                        double currPoint=nanduDesc.getPoint(l);

                        if(l % 2 == 1)//for transistion
                        {

                        }
                        else    //for difficulty
                        {
                            if(count>=minJudgeCount && currPoint>=.3)   //b level movement has .3 or greater values
                            {
                                bLevelNanduCount++;
                            }
                        }
                        break;
                    }
                    l-=nanduDesc.getTotalMovements();
                }


            }
        }

        return bLevelNanduCount;        
    }
    
    public String getSummaryJudgeB(int scoringSystem)
    {
        int i;
        String output=new String();
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeB && judgesData[i].size()>0)
                output+=String.format("%.2f",Double.valueOf(((point)judgesData[i].lastElement()).x))+" ";
        }
   
        // Head Judge's B-score
        if (judgesData[(globalData.totalJudges-1)].size() > 0) 
        {
            Double score = (Double) judgesData[(globalData.totalJudges-1)].firstElement();
            if(score!=0.0)
                output+=String.format("%.2f",Double.valueOf(score))+" ";
        }
        return output;
    }
    
    public String getSummaryNandu()
    {
        String output=new String();
        int i,j,count,k,totalMovement=getMovementsCount();
        
        int totalJudges=0,minJudgeCount=2;
        //if more than two judges think its okay
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {
            if(judgesType[i]==judge.judgeType.judgeC && judgesConnected[i]==true)
            {
               totalJudges++;
            }
        }
        if(minJudgeCount>totalJudges)
            minJudgeCount=totalJudges;

        if(minJudgeCount>0)
        {
            //check all nandu
            for(j=0; j<totalMovement;j++)
            {
                count=0;
                //if more than two judges think its okay
                for (i = 0; i < (globalData.totalJudges-1); i++)
                {       
                    if(judgesType[i]==judge.judgeType.judgeC && j<judgesData[i].size())
                    {
                        point p=(point)judgesData[i].get(j);
                        if(p.y==1)  //if success increase the counter
                            count++;                    
                    }
                }        
                int l=j;
                for(k=0;k<this.getNanduCount();k++)
                {
                    nanduData.nandu nanduDesc=globalData.nanduList.find(getNandu(k));
                    if(l<nanduDesc.getTotalMovements())
                    {
                        if(l==0)
                        {
                            if(count>=minJudgeCount)
                                output+=" pass";
                            else
                                output+=" fail";
                        }
                        else
                        {
                            if(count>=minJudgeCount)
                                output+="-pass";
                            else
                                output+="-fail";
                        }
                        break;
                    }
                    l-=nanduDesc.getTotalMovements();
                }
            }
        }
        return output;        
    }
    
    
    // this method gets the total score of the deductions by the Head Judge
    public String MarshalDeductions()
    {
        if (judgesData[(globalData.totalJudges-1)].size() > 0) {
            return String.format("%.2f", ((Double)judgesData[(globalData.totalJudges-1)].lastElement()).doubleValue());
        }
        else {
            return "0.0";
        }
    }
    
    public void UnmarshalDeductions(String raw)
    {
        if(raw.length()!=0)
        {
            double deduct = Double.parseDouble(raw);
            judgesData[(globalData.totalJudges-1)].add(deduct);
        }
    }
    
    public double calculateDeductions()
    {
        if (judgesData[(globalData.totalJudges-1)].size() > 0) {
            return ((Double)judgesData[(globalData.totalJudges-1)].lastElement()).doubleValue();
        }
        else {
            return 0.0;
        }
    }
    
    // this method calculates the athlete's final score and takes
    // head judge deductions into consideration as well 
    public double calculateFinalScore(int scoringSystem)
    {
        double AScore, BScore, CScore, Deductions;
        
        BScore = calculateBScore(scoringSystem);
        Deductions = calculateDeductions();
        // 0 Traditional System
        if(scoringSystem==0)
            return BScore - Deductions;
        AScore = calculateAScore();
        CScore = calculateCScore();
        return AScore + BScore + CScore - Deductions;
    }

    //returns deduction
    public String getDeductions()
    {
        return String.format("%.2f", calculateDeductions());
    }
    
    //returns final Score
    public String getFinalScore()
    {
        return String.format("%.2f", calculateFinalScore(globalData.scoringSystem));
    }
    
    //returns final Score
    public String getMistakeCount()
    {
        return Integer.toString(numMistakes());
    }
    
    //returns final Score
    public String getAScore()
    {
        return String.format("%.2f", calculateAScore());
    }
    
    //returns final Score
    public String getBScore()
    {
        return String.format("%.2f", calculateBScore(globalData.scoringSystem));
    }
    
    //returns final Score
    public String getCScore()
    {
        return String.format("%.2f", calculateCScore());
    }    
    
    public static class Deduction
    {
        public int judgeIndex;
        public Vector judgeData;
        public Deduction(int index, Vector data)
        {
            judgeIndex = index;
            judgeData = data;
        }
    }
    
    /*
    public Deduction generateDeduction(int index, Vector data)
    {
        return Deduction(index, data);
    }
     */
    
    public static class DeductPoint implements Comparable
    {
        public int judgeIndex;
        public int time; // in 1/100ths of a second
        public int code;
        public boolean marked;
        public DeductPoint(int judgeIndex_in, int time_in, int code_in)
        {
            judgeIndex = judgeIndex_in;
            time = time_in;
            code = code_in;
            marked = false;
        }
        
        public int compareTo(Object o)
        {
            DeductPoint other = (DeductPoint) o;
            int time_diff = time - other.time;
            int judge_diff = judgeIndex - other.judgeIndex;
            int code_diff = code - other.code;
           
            if (time_diff != 0) {
                return time_diff;
            }
            else if (judge_diff != 0) {
                return judge_diff;
            }
            else {
                return code_diff;
            }
        }
    }
    
    public static Vector computeADeductions(Vector raw_deductions)
    {
        Vector deductions = new Vector();
        Vector final_deductions = new Vector();
        
        // Move deductions into a canonical format.
        int i, j;
        for (i = 0; i < raw_deductions.size(); i++)
        {
            for (j = 0; j < ((Deduction)raw_deductions.elementAt(i)).judgeData.size(); j++) {
                int index = ((Deduction)raw_deductions.elementAt(i)).judgeIndex;
                point p = (point) ((Deduction)raw_deductions.elementAt(i)).judgeData.elementAt(j);
                
                DeductPoint new_point = new athlete.DeductPoint(index, (int) p.x, (int)p.y);
                deductions.addElement(new_point);
            }
        }
        
        // Sort deductions by time
        Collections.sort(deductions);
        
        
        int k;
        for (k = 0; k < deductions.size(); k++)
        {
            DeductPoint temp = (DeductPoint) deductions.elementAt(k);
            //System.err.println("deduct: (" + temp.judgeIndex + "," + temp.time + "," + temp.code + ") "
            //        + temp.marked);
 
            if (temp.marked == false) {
                temp.marked = true;
                
                // Search for other points with the following criteria:
                // (1) Different judgeIndex
                // (2) Closeby in time
                // (3) Same code
                // (4) Hasn't been marked globally
                // (5) Hasn't been marked locally
                Vector local_deduct = new Vector();
                local_deduct.addElement(temp);
                boolean [] localJudgeFound = new boolean[globalData.totalJudges];
                localJudgeFound[temp.judgeIndex] = true;
                int subI;
                for (subI = k + 1; subI < deductions.size(); subI++)
                {
                    DeductPoint temp2 = (DeductPoint) deductions.elementAt(subI);
                    if (temp.judgeIndex != temp2.judgeIndex && // (1) Different judgeIndex
                     temp.code == temp2.code && // (3) Same code
                     Math.abs(temp.time - temp2.time) <= (globalData.JudgeATimeRangeInSec * 100) && // (2) Closeby in time
                     temp2.marked == false && // (4) Hasn't been marked globally
                     localJudgeFound[temp2.judgeIndex] == false // (5) Hasn't been marked locally
                        )
                    {
                        temp2.marked = true; // mark globally
                        localJudgeFound[temp2.judgeIndex] = true; // mark locally
                        local_deduct.addElement(temp2); // add to local deductions
                    }
                }
                
                final_deductions.addElement(local_deduct);

            }

        }
        
        return final_deductions;
    }
   
    public String MarshalRawB(int scoringSystem)
    {
        String result = "";
        int i;
        for (i = 0; i < (globalData.totalJudges-1); i++)
        {       
            if(judgesType[i]==judge.judgeType.judgeB && judgesData[i].size()>0) {
                Double score = new Double(((point)judgesData[i].lastElement()).x);
                result += "(" + i + "," + String.format("%.2f", score) + ") ";
            }
        }
        if (judgesData[(globalData.totalJudges-1)].size() > 0) {
            Double score = (Double) judgesData[(globalData.totalJudges-1)].firstElement();
            result += "(" + (globalData.totalJudges-1) + "," + String.format("%.2f", score) + ")";
        }
        return result;
    }
    
    public void UnmarshalRawB(String raw)
    {
        StringTokenizer tokens = new StringTokenizer(raw);
        while (tokens.hasMoreTokens()) {
            String pair = tokens.nextToken();
            
            StringTokenizer subtokens = new StringTokenizer(pair, "(,)");
            int judgeIndex = Integer.parseInt(subtokens.nextToken());
            float score = Float.parseFloat(subtokens.nextToken());
            double score_d = (double) score;
            
            // insert data
            if (judgeIndex != (globalData.totalJudges-1)) {
                judgesData[judgeIndex] = new Vector();
                judgesData[judgeIndex].add(new point(score, 0));
            }
            else {
                judgesData[judgeIndex].add(score_d);
            }
        }
    }

    //sets time
    void setTime(int diffTime0)
    {
        diffTime=diffTime0;
    }
    
    //gets time
    int getTime()
    {
        return diffTime;
    }
    
}
